/**
 ****************************************************************************************************
 * @file        charset_convert.c
 * @brief       字符编码转换模块
 * @details     提供UTF8、Unicode、GBK之间的编码转换功能
 *              使用Flash中存储的GBK查表实现高效转换
 ****************************************************************************************************
 */

#include "./TEXT/charset_convert.h"
#include "./TEXT/fonts.h"
#include "./TEXT/text.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/NORFLASH/bsp_norflash.h"
#include <string.h>
#include <stdio.h>

/**
 * @brief       将Unicode编码转换成UTF8编码
 * @param       pInput: 输入的Unicode字符串
 * @param       pOutput: 输出的UTF8字符串缓冲区
 * @retval      转换后的UTF8字符串字节数，出错返回-1
 */
int unicode_to_utf8(char* pInput, char *pOutput)  
{  
    int len = 0; /* 记录转换后的UTF8字符串的字节数 */
    
    while (*pInput)
    {
        /* 处理一个Unicode字符 */
        char low = *pInput;     /* 取出Unicode字符的低8位 */
        pInput++;
        char high = *pInput;    /* 取出Unicode字符的高8位 */
        unsigned wchar = (high << 8) + low; /* 高8位和低8位组成一个Unicode字符 */
 
        if (wchar <= 0x7F) /* 英文字符 */
        {   
            pOutput[len] = (char)wchar;  /* 取wchar的低8位 */
            len++;
        }  
        else if (wchar >= 0x80 && wchar <= 0x7FF) /* 可以转换成双字节UTF8字符 */
        {  
            pOutput[len] = 0xC0 | ((wchar >> 6) & 0x1F);  /* 取出Unicode编码低6位后的5位 */
            len++;
            pOutput[len] = 0x80 | (wchar & 0x3F);  /* 取出Unicode编码的低6位 */
            len++;
        }  
        else if (wchar >= 0x800 && wchar < 0xFFFF) /* 可以转换成3个字节的UTF8字符 */
        {  
            pOutput[len] = 0xE0 | ((wchar >> 12) & 0x0F);  /* 高四位 */
            len++;
            pOutput[len] = 0x80 | ((wchar >> 6) & 0x3F);   /* 中间6位 */
            len++;
            pOutput[len] = 0x80 | (wchar & 0x3F);          /* 低6位 */
            len++;
        }  
        else /* 对于其他字节数的Unicode字符不进行处理 */
        {
            return -1;
        }
        pInput++; /* 处理下一个Unicode字符 */
    }
    
    pOutput[len] = 0; /* UTF8字符串结束符 */
    return len;  
}

/**
 * @brief       将UTF8编码转换成Unicode编码（UCS-2LE）
 * @param       pInput: 输入的UTF8字符串
 * @param       pOutput: 输出的Unicode字符串缓冲区
 * @retval      转换后的Unicode字符串字节数，出错返回-1
 */
int utf8_to_unicode(char* pInput, char* pOutput)
{
    int outputSize = 0; /* 记录转换后的Unicode字符串的字节数 */
 
    while (*pInput)
    {
        if (*pInput > 0x00 && *pInput <= 0x7F) /* 处理单字节UTF8字符（英文字母、数字） */
        {
            *pOutput = *pInput;
            pOutput++;
            *pOutput = 0; /* 小端法表示，在高地址填补0 */
        }
        else if (((*pInput) & 0xE0) == 0xC0) /* 处理双字节UTF8字符 */
        {
            char high = *pInput;
            pInput++;
            char low = *pInput;
            if ((low & 0xC0) != 0x80)  /* 检查是否为合法的UTF8字符表示 */
            {
                return -1; /* 如果不是则报错 */
            }
 
            *pOutput = (high << 6) + (low & 0x3F);
            pOutput++;
            *pOutput = (high >> 2) & 0x07;
        }
        else if (((*pInput) & 0xF0) == 0xE0) /* 处理三字节UTF8字符 */
        {
            char high = *pInput;
            pInput++;
            char middle = *pInput;
            pInput++;
            char low = *pInput;
            if (((middle & 0xC0) != 0x80) || ((low & 0xC0) != 0x80))
            {
                return -1;
            }
            *pOutput = (middle << 6) + (low & 0x3F); /* Unicode字符的低8位 */
            pOutput++;
            *pOutput = (high << 4) + ((middle >> 2) & 0x0F); /* Unicode字符的高8位 */
        }
        else /* 对于其他字节数的UTF8字符不进行处理 */
        {
            return -1;
        }
        pInput++;   /* 处理下一个UTF8字符 */
        pOutput++;
        outputSize += 2;
    }
    
    /* Unicode字符串结束符 */
    *pOutput = 0;
    pOutput++;
    *pOutput = 0;
    return outputSize;
}

/**
 * @brief       将Unicode字符转换为GBK字符（使用Flash查表）
 * @param       uni: Unicode字符值
 * @retval      对应的GBK字符，失败返回0
 * @note        基于myffunicode.c中的ff_uni2oem函数改进
 */
uint16_t unicode_to_gbk_char(uint16_t uni)
{
    uint16_t t[2];
    uint16_t c;
    uint32_t i, li, hi;
    uint16_t n;
    uint32_t gbk2uni_offset = 0;

    if (uni < 0x80)
    {
        c = uni;    /* ASCII，直接不用转换 */
    }
    else
    {
        /* 检查字库是否已初始化 */
        if (ftinfo.fontok != 0xAA)
        {
            return 0;   /* 字库未初始化 */
        }
        
        hi = ftinfo.ugbksize / 2; /* 对半开 */
        hi = hi / 4 - 1;
        li = 0;

        for (n = 16; n; n--)    /* 二分法查找 */
        {
            i = li + (hi - li) / 2;
            norflash_read((uint8_t *)&t, ftinfo.ugbkaddr + i * 4 + gbk2uni_offset, 4);  /* 读出4个字节 */

            if (uni == t[0]) break;

            if (uni > t[0])
            {
                li = i + 1;
            }
            else
            {
                hi = i - 1;
            }
        }

        if (n != 0)
        {
            c = t[1];   /* 找到对应的GBK编码 */
        }
        else
        {
            c = 0;      /* 未找到对应编码 */
        }
    }
    return c;
}

/**
 * @brief       将GBK字符转换为Unicode字符（使用Flash查表）
 * @param       gbk: GBK字符值
 * @retval      对应的Unicode字符，失败返回0
 */
uint16_t gbk_to_unicode_char(uint16_t gbk)
{
    uint16_t t[2];
    uint16_t c = 0;
    uint32_t i, li, hi;
    uint16_t n;
    uint32_t gbk2uni_offset = 0;

    if (gbk < 0x80)
    {
        c = gbk;    /* ASCII，直接不用转换 */
    }
    else
    {
        /* 检查字库是否已初始化 */
        if (ftinfo.fontok != 0xAA)
        {
            return 0;   /* 字库未初始化 */
        }
        
        hi = ftinfo.ugbksize / 2; /* 对半开 */
        hi = hi / 4 - 1;
        li = 0;

        for (n = 16; n; n--)    /* 二分法查找 */
        {
            i = li + (hi - li) / 2;
            norflash_read((uint8_t *)&t, ftinfo.ugbkaddr + i * 4 + gbk2uni_offset, 4);  /* 读出4个字节 */

            if (gbk == t[1]) break;  /* 注意：这里是查找GBK值，所以比较t[1] */

            if (gbk > t[1])
            {
                li = i + 1;
            }
            else
            {
                hi = i - 1;
            }
        }

        if (n != 0)
        {
            c = t[0];   /* 找到对应的Unicode编码 */
        }
        else
        {
            c = 0;      /* 未找到对应编码 */
        }
    }
    return c;
}

/**
 * @brief       将GBK字符串转换为UTF8字符串
 * @param       gbk_str: 输入的GBK字符串
 * @param       utf8_str: 输出的UTF8字符串缓冲区
 * @param       utf8_size: UTF8缓冲区大小
 * @retval      转换后的UTF8字符串长度，失败返回-1
 */
int gbk_to_utf8(const char* gbk_str, char* utf8_str, int utf8_size)
{
    char unicode_buf[512];  /* Unicode缓冲区 */
    int gbk_len = strlen(gbk_str);
    int unicode_len = 0;
    int utf8_len;
    int i = 0;
    uint16_t gbk_char, unicode_char;
    
    /* 检查参数 */
    if (!gbk_str || !utf8_str || utf8_size <= 0)
    {
        return -1;
    }
    
    /* GBK转Unicode */
    while (i < gbk_len)
    {
        if ((unsigned char)gbk_str[i] < 0x80)
        {
            /* ASCII字符 */
            unicode_buf[unicode_len++] = gbk_str[i];
            unicode_buf[unicode_len++] = 0;
            i++;
        }
        else
        {
            /* 双字节GBK字符 */
            if (i + 1 >= gbk_len) break;  /* 防止越界 */
            
            gbk_char = ((unsigned char)gbk_str[i] << 8) | (unsigned char)gbk_str[i + 1];
            unicode_char = gbk_to_unicode_char(gbk_char);
            
            if (unicode_char == 0)
            {
                /* 转换失败，跳过该字符 */
                i += 2;
                continue;
            }
            
            /* 存储Unicode字符（小端序） */
            unicode_buf[unicode_len++] = (char)(unicode_char & 0xFF);
            unicode_buf[unicode_len++] = (char)(unicode_char >> 8);
            i += 2;
        }
        
        /* 检查缓冲区空间 */
        if (unicode_len >= sizeof(unicode_buf) - 2)
        {
            break;
        }
    }
    
    /* Unicode字符串结束符 */
    unicode_buf[unicode_len++] = 0;
    unicode_buf[unicode_len++] = 0;
    
    /* Unicode转UTF8 */
    utf8_len = unicode_to_utf8(unicode_buf, utf8_str);
    
    return utf8_len;
}

/**
 * @brief       将UTF8字符串转换为GBK字符串
 * @param       utf8_str: 输入的UTF8字符串
 * @param       gbk_str: 输出的GBK字符串缓冲区
 * @param       gbk_size: GBK缓冲区大小
 * @retval      转换后的GBK字符串长度，失败返回-1
 */
int utf8_to_gbk(const char* utf8_str, char* gbk_str, int gbk_size)
{
    char unicode_buf[512];  /* Unicode缓冲区 */
    int unicode_len;
    int gbk_len = 0;
    int i;
    uint16_t unicode_char, gbk_char;
    
    /* 检查参数 */
    if (!utf8_str || !gbk_str || gbk_size <= 0)
    {
        return -1;
    }
    
    /* 第一步：UTF8转Unicode */
    unicode_len = utf8_to_unicode((char*)utf8_str, unicode_buf);
    if (unicode_len < 0)
    {
        return -1;
    }
    
    /* 第二步：Unicode转GBK */
    for (i = 0; i < unicode_len; i += 2)
    {
        /* 检查缓冲区空间 */
        if (gbk_len >= gbk_size - 2)
        {
            break;  /* 缓冲区不足 */
        }
        
        /* 提取Unicode字符（小端序） */
        unicode_char = (uint16_t)(unicode_buf[i] | (unicode_buf[i + 1] << 8));
        
        /* 转换为GBK */
        gbk_char = unicode_to_gbk_char(unicode_char);
        
        if (gbk_char == 0)
        {
            /* 转换失败，跳过该字符 */
            continue;
        }
        
        if (gbk_char < 0x80)
        {
            /* ASCII字符 */
            gbk_str[gbk_len++] = (char)gbk_char;
        }
        else
        {
            /* 双字节GBK字符 */
            gbk_str[gbk_len++] = (char)(gbk_char >> 8);   /* 高字节 */
            gbk_str[gbk_len++] = (char)(gbk_char & 0xFF); /* 低字节 */
        }
    }
    
    gbk_str[gbk_len] = '\0';  /* 字符串结束符 */
    return gbk_len;
}

/**
 * @brief       测试UTF8到GBK转换功能
 * @param       无
 * @retval      无
 */
void utf8_to_gbk_test(void)
{
    const char* utf8_test = "Hello 世界";
    char gbk_result[64];
    int result_len;
    
    printf("------- UTF8转GBK测试 -------\r\n");
    printf("输入UTF8: %s\r\n", utf8_test);
    
    lcd_clear(g_back_color);
    text_show_string(30, 50, 200, 16, (char*)utf8_test, 16, 0, g_point_color);
    result_len = utf8_to_gbk(utf8_test, gbk_result, sizeof(gbk_result));
    text_show_string(30, 80, 200, 16, gbk_result, 16, 0, g_point_color);
    
    if (result_len > 0)
    {
        printf("转换成功，GBK长度: %d\r\n", result_len);
        printf("GBK结果: %s\r\n", gbk_result);
    }
    else
    {
        printf("转换失败\r\n");
    }
    
    printf("----------- 测试完成 -----------\r\n");
}

/**
 * @brief       测试GBK到UTF8转换功能
 * @param       无
 * @retval      无
 */
void gbk_to_utf8_test(void)
{
    const char* gbk_test = "Hello 世界";  /* 这里应该是GBK编码的字符串 */
    char utf8_result[64];
    int result_len;
    
    printf("------- GBK转UTF8测试 -------\r\n");
    printf("输入GBK: %s\r\n", gbk_test);
    
    lcd_clear(g_back_color);
    text_show_string(30, 50, 200, 16, (char*)gbk_test, 16, 0, g_point_color);
    result_len = gbk_to_utf8(gbk_test, utf8_result, sizeof(utf8_result));
    text_show_string(30, 80, 200, 16, utf8_result, 16, 0, g_point_color);
    
    if (result_len > 0)
    {
        printf("转换成功，UTF8长度: %d\r\n", result_len);
        printf("UTF8结果: %s\r\n", utf8_result);
    }
    else
    {
        printf("转换失败\r\n");
    }
    
    printf("----------- 测试完成 -----------\r\n");
}

/**
 * @brief       测试Flash基础GBK查找表的可用性
 * @param       无
 * @retval      无
 */
void flash_gbk_table_test(void)
{
    uint16_t test_unicode[] = {0x4E16, 0x754C};  /* "世界"的Unicode编码 */
    uint16_t test_gbk[] = {0xCAC0, 0xBDE7};      /* "世界"的GBK编码 */
    uint16_t result_gbk, result_unicode;
    int i;
    
    printf("------- Flash GBK查找表测试 -------\r\n");
    
    /* 检查字库初始化状态 */
    if (ftinfo.fontok != 0xAA)
    {
        printf("错误: 字库未初始化 (fontok=0x%02X)\r\n", ftinfo.fontok);
        printf("请确保Flash字库已正确加载\r\n");
        return;
    }
    
    printf("字库状态: 已初始化 (fontok=0x%02X)\r\n", ftinfo.fontok);
    printf("GBK表地址: 0x%08X, 大小: %d\r\n", ftinfo.ugbkaddr, ftinfo.ugbksize);
    
    /* 测试Unicode到GBK转换 */
    printf("\n--- Unicode到GBK转换测试 ---\r\n");
    for (i = 0; i < 2; i++)
    {
        result_gbk = unicode_to_gbk_char(test_unicode[i]);
        printf("Unicode 0x%04X -> GBK 0x%04X (期望: 0x%04X) %s\r\n", 
               test_unicode[i], result_gbk, test_gbk[i],
               (result_gbk == test_gbk[i]) ? "✓" : "✗");
    }
    
    /* 测试GBK到Unicode转换 */
    printf("\n--- GBK到Unicode转换测试 ---\r\n");
    for (i = 0; i < 2; i++)
    {
        result_unicode = gbk_to_unicode_char(test_gbk[i]);
        printf("GBK 0x%04X -> Unicode 0x%04X (期望: 0x%04X) %s\r\n", 
               test_gbk[i], result_unicode, test_unicode[i],
               (result_unicode == test_unicode[i]) ? "✓" : "✗");
    }
    
    /* 测试ASCII字符 */
    printf("\n--- ASCII字符测试 ---\r\n");
    result_gbk = unicode_to_gbk_char('A');
    result_unicode = gbk_to_unicode_char('A');
    printf("ASCII 'A' (0x41): Unicode->GBK=0x%04X, GBK->Unicode=0x%04X %s\r\n", 
           result_gbk, result_unicode, 
           (result_gbk == 'A' && result_unicode == 'A') ? "✓" : "✗");
    
    printf("----------- 测试完成 -----------\r\n");
}
